#include <linux/module.h>
#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/slab.h>
#include "tm1629a.h"

struct tm1629a_dev {
    struct device *dev;
    int gpio_clk;
    int gpio_dio;
    int gpio_stb;
    u8 brightness;
    bool display_on;
    enum tm1629a_led_type led_type;
    enum tm1629a_addr_mode addr_mode;
    u8 num_digits;     /* 数码管数量 */
    u8 display_cache[8];  /* 显示缓存 */
    struct mutex lock;
};

/* 数码管段码定义 */
static const u8 tm1629a_digit_table[] = {
    0x3F, /* 0 */
    0x06, /* 1 */
    0x5B, /* 2 */
    0x4F, /* 3 */
    0x66, /* 4 */
    0x6D, /* 5 */
    0x7D, /* 6 */
    0x07, /* 7 */
    0x7F, /* 8 */
    0x6F, /* 9 */
    0x77, /* A */
    0x7C, /* b */
    0x39, /* C */
    0x5E, /* d */
    0x79, /* E */
    0x71, /* F */
};

/* 
 * 写入一个字节
 * 时序：
 * 1. CLK = 1, DIO = data[0]
 * 2. CLK = 0, 数据建立
 * 3. 重复8次，LSB优先
 */
static void tm1629a_write_byte(struct tm1629a_dev *tm1629a, u8 data)
{
    int i;
    
    for (i = 0; i < 8; i++) {
        /* 先设置数据，再拉低时钟 */
        gpio_set_value(tm1629a->gpio_clk, 0);
        gpio_set_value(tm1629a->gpio_dio, (data & 0x01) ? 1 : 0);
        udelay(1);  /* 数据建立时间 */
        
        /* 时钟上升沿，数据被锁存 */
        gpio_set_value(tm1629a->gpio_clk, 1);
        udelay(1);  /* 时钟高电平保持时间 */
        
        data >>= 1;
    }
}

/* 
 * 写入命令
 * 时序：
 * 1. STB = 0，选中芯片
 * 2. 写入命令字节
 * 3. STB = 1，结束传输
 */
static void tm1629a_write_cmd(struct tm1629a_dev *tm1629a, u8 cmd)
{
    gpio_set_value(tm1629a->gpio_stb, 0);
    tm1629a_write_byte(tm1629a, cmd);
    gpio_set_value(tm1629a->gpio_stb, 1);
}

/* 
 * 写入数据到指定地址
 * 时序：
 * 1. STB = 0，选中芯片
 * 2. 写入地址命令（0xC0 + addr）
 * 3. 写入数据
 * 4. STB = 1，结束传输
 */
static void tm1629a_write_data(struct tm1629a_dev *tm1629a, u8 addr, u8 data)
{
    gpio_set_value(tm1629a->gpio_stb, 0);
    
    /* 设置写入地址 */
    tm1629a_write_byte(tm1629a, TM1629A_CMD_ADDRESS_SET | addr);
    
    /* 写入数据 */
    tm1629a_write_byte(tm1629a, data);
    
    gpio_set_value(tm1629a->gpio_stb, 1);
}

/* 
 * 批量写入数据
 * 时序：
 * 1. STB = 0，选中芯片
 * 2. 写入数据命令（0x40）
 * 3. STB = 1，结束命令
 * 4. STB = 0，开始数据传输
 * 5. 写入起始地址（0xC0 + addr）
 * 6. 连续写入多个数据
 * 7. STB = 1，结束传输
 */
static void tm1629a_write_data_bulk(struct tm1629a_dev *tm1629a, u8 addr,
                                   const u8 *data, size_t len)
{
    int i;
    
    /* 设置数据写入模式 */
    gpio_set_value(tm1629a->gpio_stb, 0);
    tm1629a_write_byte(tm1629a, tm1629a->addr_mode == TM1629A_ADDR_AUTO_INC ?
                       TM1629A_DATA_WRITE_INC : TM1629A_DATA_WRITE_FIXED);
    gpio_set_value(tm1629a->gpio_stb, 1);
    
    /* 写入数据 */
    gpio_set_value(tm1629a->gpio_stb, 0);
    tm1629a_write_byte(tm1629a, TM1629A_CMD_ADDRESS_SET | addr);
    
    for (i = 0; i < len; i++) {
        tm1629a_write_byte(tm1629a, data[i]);
    }
    
    gpio_set_value(tm1629a->gpio_stb, 1);
}

static int tm1629a_parse_dt(struct tm1629a_dev *tm1629a)
{
    struct device *dev = tm1629a->dev;
    const char *led_type_str;
    u32 num_digits;
    int ret;

    /* 获取GPIO引脚 */
    tm1629a->gpio_clk = of_get_named_gpio(dev->of_node, "clk-gpios", 0);
    if (!gpio_is_valid(tm1629a->gpio_clk)) {
        dev_err(dev, "无效的时钟GPIO\n");
        return -EINVAL;
    }

    tm1629a->gpio_dio = of_get_named_gpio(dev->of_node, "dio-gpios", 0);
    if (!gpio_is_valid(tm1629a->gpio_dio)) {
        dev_err(dev, "无效的数据GPIO\n");
        return -EINVAL;
    }

    tm1629a->gpio_stb = of_get_named_gpio(dev->of_node, "stb-gpios", 0);
    if (!gpio_is_valid(tm1629a->gpio_stb)) {
        dev_err(dev, "无效的选通GPIO\n");
        return -EINVAL;
    }

    /* 获取可选的默认亮度值 */
    ret = of_property_read_u8(dev->of_node, "default-brightness", 
                             &tm1629a->brightness);
    if (ret < 0)
        tm1629a->brightness = 4; /* 默认亮度值 */

    /* 获取LED类型 */
    if (!of_property_read_string(dev->of_node, "led-type", &led_type_str)) {
        if (!strcmp(led_type_str, "common-anode"))
            tm1629a->led_type = TM1629A_COMMON_ANODE;
        else if (!strcmp(led_type_str, "common-cathode"))
            tm1629a->led_type = TM1629A_COMMON_CATHODE;
        else {
            dev_warn(dev, "未知的LED类型: %s，使用默认共阴极\n", led_type_str);
            tm1629a->led_type = TM1629A_COMMON_CATHODE;
        }
    } else {
        tm1629a->led_type = TM1629A_COMMON_CATHODE;  /* 默认使用共阴极 */
    }

    dev_info(dev, "LED类型: %s\n", 
             tm1629a->led_type == TM1629A_COMMON_ANODE ? "共阳极" : "共阴极");

    /* 获取数码管数量 */
    if (!of_property_read_u32(dev->of_node, "num-digits", &num_digits)) {
        if (num_digits > 0 && num_digits <= 8) {
            tm1629a->num_digits = num_digits;
        } else {
            dev_warn(dev, "无效的数码管数量: %u，使用默认值8\n", num_digits);
            tm1629a->num_digits = 8;
        }
    } else {
        tm1629a->num_digits = 8;  /* 默认使用8位数码管 */
    }

    dev_info(dev, "数码管数量: %u\n", tm1629a->num_digits);

    return 0;
}

static int tm1629a_gpio_init(struct tm1629a_dev *tm1629a)
{
    struct device *dev = tm1629a->dev;
    int ret;

    /* 请求GPIO资源 */
    ret = devm_gpio_request_one(dev, tm1629a->gpio_clk, 
                               GPIOF_OUT_INIT_HIGH, "tm1629a-clk");
    if (ret) {
        dev_err(dev, "无法请求CLK GPIO\n");
        return ret;
    }

    ret = devm_gpio_request_one(dev, tm1629a->gpio_dio,
                               GPIOF_OUT_INIT_HIGH, "tm1629a-dio");
    if (ret) {
        dev_err(dev, "无法请求DIO GPIO\n");
        return ret;
    }

    ret = devm_gpio_request_one(dev, tm1629a->gpio_stb,
                               GPIOF_OUT_INIT_HIGH, "tm1629a-stb");
    if (ret) {
        dev_err(dev, "无法请求STB GPIO\n");
        return ret;
    }

    /* 初始化完成后，确保STB为高电平（空闲状态） */
    gpio_set_value(tm1629a->gpio_stb, 1);

    return 0;
}

static void tm1629a_gpio_free(struct tm1629a_dev *tm1629a)
{
    /* 设置所有GPIO为高电平（空闲状态） */
    gpio_set_value(tm1629a->gpio_clk, 1);
    gpio_set_value(tm1629a->gpio_dio, 1);
    gpio_set_value(tm1629a->gpio_stb, 1);
}

/* 设置显示开关和亮度 */
static void tm1629a_set_display(struct tm1629a_dev *tm1629a, bool on, u8 brightness)
{
    u8 cmd;

    if (brightness > TM1629A_BRIGHTNESS_MAX)
        brightness = TM1629A_BRIGHTNESS_MAX;

    cmd = TM1629A_CMD_DISPLAY_CTRL | (on ? TM1629A_DISPLAY_ON : TM1629A_DISPLAY_OFF) | brightness;
    tm1629a_write_cmd(tm1629a, cmd);

    tm1629a->display_on = on;
    tm1629a->brightness = brightness;
}

/* 设置数据写入模式 */
static void tm1629a_set_write_mode(struct tm1629a_dev *tm1629a, enum tm1629a_addr_mode mode)
{
    u8 cmd = (mode == TM1629A_ADDR_AUTO_INC) ? 
             TM1629A_DATA_WRITE_INC : TM1629A_DATA_WRITE_FIXED;
    
    tm1629a_write_cmd(tm1629a, cmd);
    tm1629a->addr_mode = mode;
}

/* 初始化显示 */
static int tm1629a_display_init(struct tm1629a_dev *tm1629a)
{
    /* 默认使用地址自动增加模式 */
    tm1629a_set_write_mode(tm1629a, TM1629A_ADDR_AUTO_INC);
    
    /* 清空显示内容 */
    u8 clear_data[8] = {0};
    tm1629a_write_data_bulk(tm1629a, 0, clear_data, 8);
    
    /* 设置显示和亮度 */
    tm1629a_set_display(tm1629a, true, tm1629a->brightness);
    
    return 0;
}

/* 根据LED类型转换段码 */
static inline u8 tm1629a_convert_segments(struct tm1629a_dev *tm1629a, u8 segments)
{
    return (tm1629a->led_type == TM1629A_COMMON_ANODE) ? ~segments : segments;
}

/* 显示一个数字到指定位置，支持小数点 */
static void tm1629a_display_digit(struct tm1629a_dev *tm1629a, int pos, int digit, bool dp)
{
    u8 segments;

    if (pos < 0 || pos > 7 || digit < 0 || digit > 15)
        return;

    segments = tm1629a_digit_table[digit];
    if (dp)
        segments |= 0x80;  /* 添加小数点段 */

    /* 根据LED类型转换段码 */
    segments = tm1629a_convert_segments(tm1629a, segments);

    tm1629a_write_data(tm1629a, pos, segments);
}

/* 显示字符串，小数点与数字共用位置 */
static void tm1629a_display_string(struct tm1629a_dev *tm1629a, const char *str)
{
    int i, digit;
    bool dp;
    u8 display_data[8] = {0};  /* 始终分配8个字节，但只使用需要的部分 */
    
    mutex_lock(&tm1629a->lock);
    
    /* 设置为地址自动增加模式 */
    tm1629a_set_write_mode(tm1629a, TM1629A_ADDR_AUTO_INC);
    
    /* 显示字符串 */
    for (i = 0; str[i] && i < tm1629a->num_digits; i++) {
        dp = (str[i+1] == '.');  /* 检查下一个字符是否为小数点 */
        
        if (str[i] >= '0' && str[i] <= '9') {
            digit = str[i] - '0';
        } else if (str[i] >= 'a' && str[i] <= 'f') {
            digit = str[i] - 'a' + 10;
        } else if (str[i] >= 'A' && str[i] <= 'F') {
            digit = str[i] - 'A' + 10;
        } else if (str[i] == '.') {
            /* 如果当前字符是小数点，跳过 */
            continue;
        } else {
            continue;
        }
        
        display_data[i] = tm1629a_convert_segments(tm1629a, 
                         tm1629a_digit_table[digit] | (dp ? 0x80 : 0));
    }
    
    /* 一次性写入所有数据 */
    tm1629a_write_data_bulk(tm1629a, 0, display_data, tm1629a->num_digits);
    
    mutex_unlock(&tm1629a->lock);
}

/* 清空显示 */
static void tm1629a_clear_display(struct tm1629a_dev *tm1629a)
{
    int i;
    
    mutex_lock(&tm1629a->lock);
    for (i = 0; i < tm1629a->num_digits; i++) {
        tm1629a_write_data(tm1629a, i, 0);
    }
    mutex_unlock(&tm1629a->lock);
}

/* sysfs接口 */
static ssize_t brightness_show(struct device *dev,
                             struct device_attribute *attr, char *buf)
{
    struct tm1629a_dev *tm1629a = dev_get_drvdata(dev);
    return sprintf(buf, "%u\n", tm1629a->brightness);
}

static ssize_t brightness_store(struct device *dev,
                              struct device_attribute *attr,
                              const char *buf, size_t count)
{
    struct tm1629a_dev *tm1629a = dev_get_drvdata(dev);
    unsigned long brightness;
    int ret;

    ret = kstrtoul(buf, 10, &brightness);
    if (ret)
        return ret;

    if (brightness > TM1629A_BRIGHTNESS_MAX)
        return -EINVAL;

    mutex_lock(&tm1629a->lock);
    tm1629a_set_display(tm1629a, tm1629a->display_on, brightness);
    mutex_unlock(&tm1629a->lock);

    return count;
}

static ssize_t display_on_show(struct device *dev,
                              struct device_attribute *attr, char *buf)
{
    struct tm1629a_dev *tm1629a = dev_get_drvdata(dev);
    return sprintf(buf, "%d\n", tm1629a->display_on);
}

static ssize_t display_on_store(struct device *dev,
                               struct device_attribute *attr,
                               const char *buf, size_t count)
{
    struct tm1629a_dev *tm1629a = dev_get_drvdata(dev);
    bool on;
    int ret;

    ret = kstrtobool(buf, &on);
    if (ret)
        return ret;

    mutex_lock(&tm1629a->lock);
    tm1629a_set_display(tm1629a, on, tm1629a->brightness);
    mutex_unlock(&tm1629a->lock);

    return count;
}

static ssize_t display_text_store(struct device *dev,
                                 struct device_attribute *attr,
                                 const char *buf, size_t count)
{
    struct tm1629a_dev *tm1629a = dev_get_drvdata(dev);
    char text[9];  /* 保持9字节缓冲区，但根据实际数码管数量限制输入 */

    if (count > tm1629a->num_digits + 1)  /* +1 for '\0' */
        return -EINVAL;

    memcpy(text, buf, count);
    text[count] = '\0';
    if (text[count - 1] == '\n')
        text[count - 1] = '\0';

    tm1629a_display_string(tm1629a, text);

    return count;
}

/* 解析段名称为段码 */
static int tm1629a_parse_segments(const char *str)
{
    int segments = 0;
    const char *p = str;
    
    while (*p) {
        /* 跳过分隔符 */
        while (*p == '|' || *p == ' ' || *p == '\t')
            p++;
            
        /* 解析段名 */
        switch (toupper(*p)) {
            case 'A': segments |= TM1629A_SEG_A; break;
            case 'B': segments |= TM1629A_SEG_B; break;
            case 'C': segments |= TM1629A_SEG_C; break;
            case 'D': segments |= TM1629A_SEG_D; break;
            case 'E': segments |= TM1629A_SEG_E; break;
            case 'F': segments |= TM1629A_SEG_F; break;
            case 'G': segments |= TM1629A_SEG_G; break;
            case 'P': segments |= TM1629A_SEG_DP; break;  /* DP或P表示小数点 */
            case '.': segments |= TM1629A_SEG_DP; break;
            case '\0': goto done;
            default: return -EINVAL;  /* 无效的段名 */
        }
        p++;
    }

done:
    return segments;
}

/* 设置指定位置的段 */
static ssize_t segments_store(struct device *dev,
                              struct device_attribute *attr,
                              const char *buf, size_t count)
{
    struct tm1629a_dev *tm1629a = dev_get_drvdata(dev);
    int pos, segments;
    char seg_str[32];
    
    /* 格式：<位置> <段名列表> */
    if (sscanf(buf, "%d %31s", &pos, seg_str) != 2)
        return -EINVAL;
    
    /* 检查位置是否有效 */
    if (pos < 0 || pos >= tm1629a->num_digits)
        return -EINVAL;
    
    /* 解析段名 */
    segments = tm1629a_parse_segments(seg_str);
    if (segments < 0)
        return segments;
    
    /* 写入段码 */
    mutex_lock(&tm1629a->lock);
    tm1629a_write_data(tm1629a, pos, segments);
    mutex_unlock(&tm1629a->lock);
    
    return count;
}

/* 读取指定位置的段 */
static ssize_t segments_show(struct device *dev,
                             struct device_attribute *attr,
                             char *buf)
{
    struct tm1629a_dev *tm1629a = dev_get_drvdata(dev);
    int pos, len = 0;
    u8 segments;
    
    /* 显示所有位置的段码 */
    for (pos = 0; pos < tm1629a->num_digits; pos++) {
        segments = tm1629a->display_cache[pos];  /* 使用缓存的段码 */
        len += sprintf(buf + len, "%d: ", pos);
        
        if (segments & TM1629A_SEG_A) len += sprintf(buf + len, "A");
        if (segments & TM1629A_SEG_B) len += sprintf(buf + len, "B");
        if (segments & TM1629A_SEG_C) len += sprintf(buf + len, "C");
        if (segments & TM1629A_SEG_D) len += sprintf(buf + len, "D");
        if (segments & TM1629A_SEG_E) len += sprintf(buf + len, "E");
        if (segments & TM1629A_SEG_F) len += sprintf(buf + len, "F");
        if (segments & TM1629A_SEG_G) len += sprintf(buf + len, "G");
        if (segments & TM1629A_SEG_DP) len += sprintf(buf + len, ".");
        
        len += sprintf(buf + len, "\n");
    }
    
    return len;
}

static DEVICE_ATTR_RW(brightness);
static DEVICE_ATTR_RW(display_on);
static DEVICE_ATTR_WO(display_text);
static DEVICE_ATTR_RW(addr_mode);
static DEVICE_ATTR_RO(num_digits);
static DEVICE_ATTR_RO(led_type);
static DEVICE_ATTR_RW(segments);

static struct attribute *tm1629a_attrs[] = {
    &dev_attr_brightness.attr,
    &dev_attr_display_on.attr,
    &dev_attr_display_text.attr,
    &dev_attr_addr_mode.attr,
    &dev_attr_num_digits.attr,
    &dev_attr_led_type.attr,
    &dev_attr_segments.attr,
    NULL
};
ATTRIBUTE_GROUPS(tm1629a);

static int tm1629a_probe(struct platform_device *pdev)
{
    struct tm1629a_dev *tm1629a;
    struct device *dev = &pdev->dev;  /* 修复：正确获取device指针 */
    int ret;

    tm1629a = devm_kzalloc(dev, sizeof(*tm1629a), GFP_KERNEL);
    if (!tm1629a)
        return -ENOMEM;

    tm1629a->dev = dev;
    mutex_init(&tm1629a->lock);
    platform_set_drvdata(pdev, tm1629a);

    /* 解析设备树 */
    if (dev->of_node) {
        ret = tm1629a_parse_dt(tm1629a);
        if (ret) {
            dev_err(dev, "设备树解析失败\n");
            return ret;
        }
    } else {
        dev_err(dev, "未找到设备树节点\n");
        return -ENODEV;
    }

    /* 初始化GPIO */
    ret = tm1629a_gpio_init(tm1629a);
    if (ret) {
        dev_err(dev, "GPIO初始化失败\n");
        return ret;
    }

    /* 初始化显示 */
    ret = tm1629a_display_init(tm1629a);
    if (ret) {
        dev_err(dev, "显示初始化失败\n");
        return ret;
    }

    /* 创建sysfs接口 */
    ret = sysfs_create_groups(&dev->kobj, tm1629a_groups);
    if (ret) {
        dev_err(dev, "无法创建sysfs接口\n");
        return ret;
    }

    dev_info(dev, "TM1629A驱动初始化成功\n");
    return 0;
}

static int tm1629a_remove(struct platform_device *pdev)
{
    struct tm1629a_dev *tm1629a = platform_get_drvdata(pdev);
    struct device *dev = tm1629a->dev;

    /* 移除sysfs接口 */
    sysfs_remove_groups(&dev->kobj, tm1629a_groups);

    /* 关闭显示 */
    tm1629a_set_display(tm1629a, false, 0);
    
    /* 清理GPIO状态 */
    tm1629a_gpio_free(tm1629a);
    
    dev_info(tm1629a->dev, "TM1629A驱动移除\n");
    return 0;
}

static const struct of_device_id tm1629a_of_match[] = {
    { .compatible = "titan,tm1629a" },
    { }
};
MODULE_DEVICE_TABLE(of, tm1629a_of_match);

static struct platform_driver tm1629a_driver = {
    .probe = tm1629a_probe,
    .remove = tm1629a_remove,
    .driver = {
        .name = "tm1629a",
        .of_match_table = tm1629a_of_match,
    },
};

module_platform_driver(tm1629a_driver);

MODULE_AUTHOR("Your Name <your.email@example.com>");
MODULE_DESCRIPTION("TM1629A LED Driver");
MODULE_LICENSE("GPL v2");

/* 地址模式控制 */
static ssize_t addr_mode_show(struct device *dev,
                              struct device_attribute *attr, char *buf)
{
    struct tm1629a_dev *tm1629a = dev_get_drvdata(dev);
    return sprintf(buf, "%s\n", 
           tm1629a->addr_mode == TM1629A_ADDR_AUTO_INC ? "auto" : "fixed");
}

static ssize_t addr_mode_store(struct device *dev,
                               struct device_attribute *attr,
                               const char *buf, size_t count)
{
    struct tm1629a_dev *tm1629a = dev_get_drvdata(dev);
    
    if (sysfs_streq(buf, "auto"))
        tm1629a_set_write_mode(tm1629a, TM1629A_ADDR_AUTO_INC);
    else if (sysfs_streq(buf, "fixed"))
        tm1629a_set_write_mode(tm1629a, TM1629A_ADDR_FIXED);
    else
        return -EINVAL;
    
    return count;
}

/* 显示数码管数量 */
static ssize_t num_digits_show(struct device *dev,
                               struct device_attribute *attr, char *buf)
{
    struct tm1629a_dev *tm1629a = dev_get_drvdata(dev);
    return sprintf(buf, "%u\n", tm1629a->num_digits);
}

/* LED类型显示 */
static ssize_t led_type_show(struct device *dev,
                             struct device_attribute *attr, char *buf)
{
    struct tm1629a_dev *tm1629a = dev_get_drvdata(dev);
    return sprintf(buf, "%s\n", 
           tm1629a->led_type == TM1629A_COMMON_ANODE ? "common-anode" : "common-cathode");
} 